//{==================================================================================================
//! @file ListLinking.cpp
//! @date 2013-09-28
//! @mainpage training program for the creation and destruction of a doubly linked list in memory
//! @author Kirill Shcherbatov <kshcherbatov@gmail.com>, 376 group, DCAM MIPT
//! @version 1.0
//}===================================================================================================

//****************************************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//****************************************************************************************************

//****************************************************************************************************
//! Enable debug mode
#define _EJC
//****************************************************************************************************

//****************************************************************************************************
//! @def   OUT
//! @note  -Use OUT to print your text in console. It is checking _EJC declaration.
//! @note  -Only if _EJC is defined then the program prints your text.
//! @note  --You also can define _EJC in compilation command (g++ main.cpp -D _EJC)
//----------------------------------------------------------------------------------------------------
//! @def    VALID
//! @param  CONDITIONAL for checking
//! @note In _EJC mode it's standart assert, which disasabling in realise
//----------------------------------------------------------------------------------------------------
#ifdef _EJC
    #define OUT        printf
    #define VALID( CONDITIONAL)      \
        {                            \
            assert(CONDITIONAL);     \
        }
#else
    #define OUT if (0) printf
    #define VALID( CONDITIONAL)      \
        {                            \
            CONDITIONAL;             \
        }
#endif
//***************************************************************************************************


//***************************************************************************************************
//     Structures
//---------------------------------------------------------------------------------------------------
struct tnode
{
    double info;
    struct tnode *next,
                 *prev;
};
//***************************************************************************************************

//***************************************************************************************************
//		Functions
//---------------------------------------------------------------------------------------------------
        int new_tnode      (tnode** item,   double value);
inline  int link_tnodes    (tnode** item1, tnode** item2);
inline  int delete_tnode   (tnode** item                );
//***************************************************************************************************


//****************************************************************************************************
//! @param - number of sending arguments
//! @param argv[] - arguments, include generated by OS
//! @return 0 on success
//----------------------------------------------------------------------------------------------------
int main (int, const char* argv[])
{
    #define $SEP_PATTERN "><><><><><><><><><><><><><><><><><><><><><><><>><><><><><><><><><><><><><><><><\n"

    OUT ( "%s \n(%s)\n%s %s:\n\n", argv[ 0 ], __FILE__, __DATE__, __TIME__ );
    OUT($SEP_PATTERN);
    OUT ("#  Hello everyone!\n"
         "#  This is for technology of dynamic doubly-linked list demonstration.\n"
         "#  We will create multiple entries and connect them together.\n");
    OUT ($SEP_PATTERN"\n");

    #undef $SEP_PATTERN;

    tnode* last = NULL;
    VALID (new_tnode (&last, rand() % 100) == 0);

    OUT ("# I'm going get some memory, & fill it with random values, lower 100...\t");

    const int need_create = 10;

    for (int i=0; i<need_create; i++)
    {
         tnode* temp_node = NULL;
         VALID (new_tnode (&temp_node, rand() % 100) == 0);
         VALID (link_tnodes (&last, &temp_node) == 0);
         last = temp_node;
    }

    OUT ("OK.\n"
         "# Dynamic data structures created successfully.\n\n");

    OUT ("# Now let's output them\n\n");

    #define $SEP_STAR "********************************************************************************\n"

    #define NODE_OUT( NODE_NAME)                                                                        \
    {                                                                                                   \
        OUT($SEP_STAR);                                                                                 \
        OUT ("# It, there is a node in memory by adress %d\n", NODE_NAME);                              \
        OUT ("# It contains information = %lg\n",  NODE_NAME -> info);                                  \
        OUT ("# Memory address of the next node is %d\n",   NODE_NAME -> next);                         \
        OUT ("# Memory address of the previous node is = %d\n\n", NODE_NAME -> prev);                   \
        OUT ("# <X> This record will be destroyed...\t");                                               \
    }

    while (last->prev != NULL)
    {

        NODE_OUT (last);

        tnode* temp_node = last;
        last = (temp_node -> prev);

        VALID (delete_tnode (&temp_node) == 0);

        OUT ("OK.\n\n");
    }

    NODE_OUT (last);

    #undef  NODE_OUT( NODE_NAME )

    free (last);
    last = NULL;

    OUT ("OK.\n\n"
         $SEP_STAR
         $SEP_STAR
         "\n"
         "# >>> Look, friend! That is all! Hi again!)\n");

    #undef $SEP_STAR

    return 0;
}
//***************************************************************************************************


//***************************************************************************************************
//! @param   item to inicialize by adress of getted memory part
//! @param   value to store
//! @note    use this to prepare new tnodes to using
//---------------------------------------------------------------------------------------------------
int new_tnode (tnode** item, double value)
{
    *item = (tnode*)calloc (1, sizeof (struct tnode));
    VALID (*item != NULL);

    (*item) -> info = value;
    (*item) -> prev = NULL;
    (*item) -> next = NULL;

    return 0;
}
//***************************************************************************************************


//***************************************************************************************************
//! @param   item1
//! @param   item2
//! @note    organizes the mutual dependence of the elements
//---------------------------------------------------------------------------------------------------
inline int link_tnodes (tnode** item1, tnode** item2)
{
    VALID (*item1 != NULL);
    VALID (*item2 != NULL);

    (*item1) -> next = *item2;
    (*item2) -> prev = *item1;

    return 0;
}
//***************************************************************************************************


//***************************************************************************************************
//! @param   itemt destroy
//! @note    use this to free memory
//---------------------------------------------------------------------------------------------------
inline int delete_tnode (tnode** item)
{
    VALID (*item != NULL);
    tnode* temp_node = (*item) -> prev;
    temp_node -> next = NULL;

    free (*item);
    *item=NULL;

    return 0;
}
//***************************************************************************************************
